/***************************************************************************************
* Copyright (c) 2014-2022 Zihao Yu, Nanjing University
*
* NEMU is licensed under Mulan PSL v2.
* You can use this software according to the terms and conditions of the Mulan PSL v2.
* You may obtain a copy of Mulan PSL v2 at:
*          http://license.coscl.org.cn/MulanPSL2
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*
* See the Mulan PSL v2 for more details.
***************************************************************************************/

#include "sdb.h"
#include "memory/vaddr.h"

#define NR_WP 32

typedef struct watchpoint {
  int NO;
  struct watchpoint *next;

  char expr[64];

  // vaddr_t vaddr;
  word_t value;
  // int len;
  /* TODO: Add more members if necessary */

} WP;

static WP wp_pool[NR_WP] = {};
static WP *head = NULL, *free_ = NULL;
void scan_all_wps();

void init_wp_pool() {
  int i;
  for (i = 0; i < NR_WP; i ++) {
    wp_pool[i].NO = i;
    wp_pool[i].next = (i == NR_WP - 1 ? NULL : &wp_pool[i + 1]);
    wp_pool[i].value = 0;
  }

  head = NULL;
  free_ = wp_pool;
}
void scan_all_wps() {
  WP *wp = head;
  while(wp != NULL) {
    bool success = false;
    word_t new_val = expr(wp->expr,&success);
    if(success == false) {
      printf("expr('%s') error\n",wp->expr);
    } else if(new_val != wp->value ) {
      printf("expr('%s') value have changed. from %lx to %lx\n",wp->expr,wp->value,new_val);
      wp->value = new_val;
      nemu_state.state = NEMU_STOP;
    }

    wp = wp->next;
  }
}
void print_all_wp() {
  WP *wp = head;
  printf("Watch points:\n");
  while(wp != NULL) {
    printf("NO:%d expr:%s value:0x%lx\n",wp->NO,wp->expr,wp->value);
    wp = wp->next;
  }
}

int set_wp(char *str,int len) {

  bool success = false;
  word_t val = expr(str,&success);
  if(success == false) return -1; 

  WP *wp = free_;
  if(wp == NULL) return -1; /*All watchpoints have been used.*/
  free_ = free_->next;

  memcpy(wp->expr,str,len);
  wp->value = val;
  /*add the wp to the list head*/
  wp->next = head;
  head = wp;
  
  return wp->NO;
}

int del_wp(int NO) {
  WP *wp = head;
  WP *last = NULL;
  while(wp != NULL && wp->NO != NO) {
    last = wp;
    wp = wp->next;
  }

  if(wp != NULL) {
    if(last != NULL) last->next = wp->next;
    wp->next = free_;
    free_ = wp;
    return wp->NO;
  }
  return -1;
}

/* TODO: Implement the functionality of watchpoint */

